using System;
using System.Net.Sockets;
using System.IO;
using System.Text;
using System.Collections;
using System.Windows.Forms;

namespace NGNntpPlugIn
{
	public class NntpException : ApplicationException
	{
		public NntpException(string message) : base(message)
		{
		}
	}

	public class Nntp : TcpClient
	{
		private bool m_isConnected = false;

		public bool IsConnected
		{
			get { return m_isConnected; }
		}

		public void Connect(string server)
		{
			if(!this.IsConnected)
			{
			string response;
 
			Connect(server, 119);
			response = Response();
			if (response.Substring( 0, 3) != "200")
			{
				throw new NntpException(response);
			}
				m_isConnected = true;
			}
		}

		public void Connect(string server, string username, string password)
		{
			if(!this.IsConnected)
			{
			string response;
			string message;

			Connect(server, 119);
			response = Response();
			if(response.Substring(0, 3) != "200")
				throw new NntpException(response);

			// attempt to authenticate, send the username
			message = "AUTHINFO USER " + username + "\r\n";
			Write(message);
			response = Response();
				if(response.Substring(0, 3) != "381" && response.Substring(0, 3) != "281")
				throw new NntpException(response);

				// send the password if needed
				if(response.Substring(0, 3) == "381")
				{
			message = "AUTHINFO PASS " + password + "\r\n";
			Write(message);
			response = Response();
			if(response.Substring(0, 3) != "281")
				throw new NntpException(response);
				}

				m_isConnected = true;
			}
		}

		public void Disconnect()
		{
			if(this.IsConnected)
			{
			string message;
			string response;
 
			message = "QUIT\r\n";
			Write(message);
			response = Response();
				if (response.Substring(0, 3) != "205")
			{
				throw new NntpException(response);
			}

				m_isConnected = false;
			}
		}

		public ArrayList GetNewsgroups()
		{
			if(this.IsConnected)
			{
			string message;
			string response;
 
			ArrayList retval = new ArrayList();
 
			message = "LIST\r\n";
			Write(message);
			response = Response();
			if (response.Substring( 0, 3) != "215")
			{
				throw new NntpException(response);
			}
 
			while (true)
			{
				response = Response();
				if (response == ".\r\n" ||
					response == ".\n")
				{
					return retval;
				}
				else
				{
					char[] seps = { ' ' };
					string[] values =
						response.Split(seps);
					retval.Add(values[0]);
					continue;
				}
			}
		}
			else
				throw new NntpException("Not Connected to Server");
		}

		public ArrayList GetNews(string newsgroup)
		{
			if(this.IsConnected)
			{
			string message;
			string response;
 
			ArrayList retval = new ArrayList();
 
			message = "GROUP " + newsgroup + "\r\n";
			Write(message);
			response = Response();
				if (response.Substring(0, 3) != "211")
			{
				throw new NntpException(response);
			}
 
			char[] seps = { ' ' };
			string[] values = response.Split(seps);
 
			long start = Int32.Parse(values[2]);
			long end = Int32.Parse(values[3]);
 
			if (start+100 < end && end > 100)
			{
				start = end-100;
			}
 
			for (long i=start;i<end;i++)
			{
				message = "ARTICLE " + i + "\r\n";
				Write(message);
				response = Response();
				if (response.Substring( 0, 3) == "423")
				{
					continue;
				}
				if (response.Substring( 0, 3) != "220")
				{
					throw new NntpException(response);
				}
 
				string article = "";
				while (true)
				{
					response = Response();
					if (response == ".\r\n")
					{
						break;
					}
 
					if (response == ".\n")
					{
						break;
					}
                        
					if (article.Length < 1024)
					{
						article += response;
					};
				}
 
				retval.Add(article);
			}
 
			return retval;
		}
			else
				throw new NntpException("Not Connected to Server");
		}

		public void Post(string newsgroup, string subject, string from, string content)
		{
			if(this.IsConnected)
			{
			string message;
			string response;
 
			message = "POST\r\n";
			Write(message);
			response = Response();

			if (response.Substring(0, 3) != "340")
			{
				throw new NntpException(response);
			}
			message = "From: " + from + "\r\n"
					+ "To: " + newsgroup + "\r\n"
				+ "Newsgroups: " + newsgroup + "\r\n"
				+ "Subject: " + subject + "\r\n\r\n"
				+ content + "\r\n.\r\n";
			Write(message);
			response = Response();
			if (response.Substring( 0, 3) != "240")
			{
				throw new NntpException(response);
			}
		}
			else
				throw new NntpException("Not Connected to Server");
		}

		public void Post(string newsgroup, string subject, string from, string content, string references)
		{
			if(this.IsConnected)
			{
			if(references == "")
			{
				Post(newsgroup, subject, from, content);
			}
			else
			{
				string message;
				string response;
 
				message = "POST\r\n";
				Write(message);
				response = Response();
				if (response.Substring(0, 3) != "340")
				{
					throw new NntpException(response);
				}
				message = "From: " + from + "\r\n"
						+ "To: " + newsgroup + "\r\n"
					+ "Newsgroups: " + newsgroup + "\r\n"
					+ "Subject: " + subject + "\r\n"
					+ "References: " + references + "\r\n\r\n"
					+ content + "\r\n.\r\n";
				Write(message);
				response = Response();
				if (response.Substring( 0, 3) != "240")
				{
					throw new NntpException(response);
				}
			}
		}
			else
				throw new NntpException("Not Connected to Server");
		}

		private void Write(string message)
		{
			System.Text.ASCIIEncoding en = new System.Text.ASCIIEncoding();
 
			byte[] WriteBuffer = new byte[1024];
			WriteBuffer = en.GetBytes(message);
 
			NetworkStream stream = GetStream();
			stream.Write(WriteBuffer,0,WriteBuffer.Length);
		}

		private string Response()
		{
			System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
			byte []serverbuff = new Byte[1024];
			NetworkStream stream = GetStream();
			int count = 0;
			while (true)
			{
				byte []buff = new Byte[2];
				int bytes = stream.Read( buff, 0, 1 );    
				if (bytes == 1)
				{
					serverbuff[count] = buff[0];
					count++;
 
					if (buff[0] == '\n')
					{
						break;
					}
				}
				else
				{
					break;
				};
			};
 
			string retval = enc.GetString( serverbuff, 0, count );
			return retval;
		}


	}
}
